package com.tlgen.orm.support;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tlgen.orm.model.PageResult;
import com.tlgen.orm.utils.dataSource.DBUtils;
import com.tlgen.orm.utils.log.TraceLog;
import com.tlgen.orm.utils.orm.CursorUtils;
import com.tlgen.orm.utils.orm.ORMUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.tlgen.orm.constant.QueryOperatorConstant.DEFAULT_PAGE_SIZE;
import static com.tlgen.orm.utils.orm.AssociationProcessor.processAssociations;
import static com.tlgen.orm.utils.orm.AssociationProcessor.processCollections;

@Slf4j
public class ModelExecutor {

    // 使用静态 final 确保线程安全且唯一实例
    private static final JdbcTemplate JT = DBUtils.get();

    // 元数据缓存
    private static final Map<Class<?>, String> PRIMARY_KEY_CACHE = new ConcurrentHashMap<>();

    /**
     * 安全执行带实体参数的SQL
     * 添加SQL验证防止注入攻击
     */
    public static <T> void execute(T t, String sql) {
        validateSql(sql); // SQL安全验证

        JT.update(
                con -> con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS),
                new GeneratedKeyHolder()
        );
    }

    /**
     * 高性能无参SQL执行
     * 自动识别批量操作
     */
    public static void execute(String sql) {
        validateSql(sql); // SQL安全验证

        // 自动判断是否为批量操作
        if (isBatchOperation(sql)) {
            JT.batchUpdate(sql);
        } else {
            JT.update(sql);
        }
    }

    // SQL安全验证（防止注入）
    private static void validateSql(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL不能为空");
        }

        // 禁用高风险操作
        String lowerSql = sql.toLowerCase();
        if (lowerSql.contains(";") ||
                lowerSql.matches("(?i).*\\b(drop|truncate|shutdown)\\b.*")) {
            throw new SecurityException("禁止执行高危SQL: " + sql);
        }
    }

    // 判断是否为批量操作
    private static boolean isBatchOperation(String sql) {
        return sql.toLowerCase().contains("insert") ||
                sql.toLowerCase().contains("update");
    }

    // 处理 select 返回单条
    public static <T> T selectSingleResult(String sql, Class<T> tClass) {
        List<T> result = selectResult(sql, tClass);
        return CollUtil.isEmpty(result) ? null : result.get(0);
    }

    // 处理 select 查询返回列表
    public static <T> List<T> selectResult(String sql, Class<T> tClass) {
        // 获取主键名称(使用缓存)
        String primaryKey = PRIMARY_KEY_CACHE.computeIfAbsent(tClass, ORMUtils::getPrimaryKey);

        // 查询主表数据
        List<T> masterList = JT.query(sql, new BeanPropertyRowMapper<>(tClass));
        if (CollectionUtils.isEmpty(masterList)) {
            return masterList;
        }

        // 转换为JSON对象列表(避免多次序列化)
        List<JSONObject> jsonObjects = masterList.stream()
                .map(obj -> JSON.parseObject(JSON.toJSONString(obj)))
                .collect(Collectors.toList());

        // 处理一对一关联
        processAssociations(jsonObjects, primaryKey, tClass, JT);

        // 处理一对多关联
        processCollections(jsonObjects, primaryKey, tClass, JT);

        // 转换回目标类型
        return jsonObjects.stream()
                .map(json -> JSON.parseObject(json.toJSONString(), tClass))
                .collect(Collectors.toList());
    }

    // 处理 select 分页查询返回列表
    public static <T> PageResult<T> selectPageResult(String sql, Class<T> tClass) {
        PageResult<T> pageResult = PageResult.<T>builder().build();

        // 获取主键名称(使用缓存)
        String primaryKey = PRIMARY_KEY_CACHE.computeIfAbsent(tClass, ORMUtils::getPrimaryKey);

        // 查询主表数据
        List<T> masterList = JT.query(sql, new BeanPropertyRowMapper<>(tClass));
        if (CollectionUtils.isEmpty(masterList)) {
            pageResult.setRecords(Collections.emptyList());
            pageResult.setTotal(0);
            return pageResult;
        }

        // 转换为JSON对象列表
        List<JSONObject> jsonObjects = masterList.stream()
                .map(obj -> JSON.parseObject(JSON.toJSONString(obj)))
                .collect(Collectors.toList());

        // 处理关联关系
        processAssociations(jsonObjects, primaryKey, tClass, JT);
        processCollections(jsonObjects, primaryKey, tClass, JT);

        // 设置记录
        pageResult.setRecords(jsonObjects.stream()
                .map(json -> JSON.parseObject(json.toJSONString(), tClass))
                .collect(Collectors.toList()));

        // 查询总记录数(使用更安全的方式)
        String countSql = buildCountSql(sql);
        TraceLog.out("Count SQL: " + countSql);

        Integer count = JT.queryForObject(countSql, Integer.class);
        pageResult.setTotal(count != null ? count : 0);

        // 解析分页参数(使用正则表达式更健壮)
        parsePaginationParams(sql, pageResult);

        return pageResult;
    }

    // 构建安全的 COUNT 查询 SQL
    private static String buildCountSql(String originalSql) {
        // 移除ORDER BY子句
        String cleanedSql = originalSql.replaceAll("(?i)ORDER\\s+BY.*", "");

        // 移除LIMIT子句
        cleanedSql = cleanedSql.replaceAll("(?i)LIMIT\\s+\\d+\\s*(,\\s*\\d+)?", "");

        // 构建COUNT查询
        return "SELECT COUNT(1) FROM (" + cleanedSql + ") total_count";
    }

    // 解析分页参数
    private static void parsePaginationParams(String sql, PageResult<?> pageResult) {
        // 使用正则表达式匹配LIMIT子句
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
                "LIMIT\\s*(\\d+)\\s*,\\s*(\\d+)",
                java.util.regex.Pattern.CASE_INSENSITIVE
        );

        java.util.regex.Matcher matcher = pattern.matcher(sql);
        if (matcher.find()) {
            try {
                int offset = Integer.parseInt(matcher.group(1));
                int pageSize = Integer.parseInt(matcher.group(2));
                int pageNum = (offset / pageSize) + 1;

                pageResult.setPageNum(pageNum);
                pageResult.setPageSize(pageSize);
            } catch (NumberFormatException e) {
                throw new RuntimeException("Failed to parse pagination params", e);
            }
        }
    }

    // 游标分页实现
    public static <T> PageResult<T> selectCursorPageResult(String sql, Class<T> tClass) {

        PageResult<T> pageResult = PageResult.<T>builder().build();

        // 获取主键名称(使用缓存)
        String primaryKey = PRIMARY_KEY_CACHE.computeIfAbsent(tClass, ORMUtils::getPrimaryKey);

        // 1. 查询主表数据（不执行COUNT查询）
        List<T> masterList = JT.query(sql, new BeanPropertyRowMapper<>(tClass));
        if (CollectionUtils.isEmpty(masterList)) {
            pageResult.setRecords(Collections.emptyList());
            pageResult.setHasNext(false);
            return pageResult;
        }

        // 转换为JSON对象列表
        List<JSONObject> jsonObjects = masterList.stream()
                .map(obj -> JSON.parseObject(JSON.toJSONString(obj)))
                .collect(Collectors.toList());

        // 处理关联关系
        processAssociations(jsonObjects, primaryKey, tClass, JT);
        processCollections(jsonObjects, primaryKey, tClass, JT);

        // 设置记录
        pageResult.setRecords(jsonObjects.stream()
                .map(json -> JSON.parseObject(json.toJSONString(), tClass))
                .collect(Collectors.toList()));

        // ====== 关键：计算是否有下一页 ======
        // 1. 从SQL中解析LIMIT限制
        int requestedSize = extractLimitSize(sql);

        // 2. 判断实际返回记录数
        boolean hasNext = masterList.size() == requestedSize;
        pageResult.setHasNext(hasNext);

        // 3. 如果还有下一页，设置游标值
        if (hasNext) {
            setNextCursor(pageResult, masterList);
        }

//        // 可选的总数查询
//        if (needTotal) {
//            String countSql = buildCountSql(sql);
//            TraceLog.out("Count SQL: " + countSql);
//            Integer count = JT.queryForObject(countSql, Integer.class);
//            pageResult.setTotal(count != null ? count : 0);
//        } else {
//            // 游标分页不需要总数时的默认值
//            pageResult.setTotal(-1);
//        }

        return pageResult;
    }

    // 从SQL中提取LIMIT大小
    private static int extractLimitSize(String sql) {
        // 尝试匹配最后的分页参数
        Matcher matcher = Pattern.compile("LIMIT\\s*\\d+\\s*(,\\s*(\\d+))?", Pattern.CASE_INSENSITIVE)
                .matcher(sql);
        if (matcher.find()) {
            try {
                // MySQL格式: LIMIT offset, size
                if (matcher.group(2) != null) {
                    return Integer.parseInt(matcher.group(2));
                }
                // PostgreSQL格式: LIMIT size
                return Integer.parseInt(matcher.group(0).replaceAll("\\D", ""));
            } catch (NumberFormatException e) {
                // 默认返回默认大小
            }
        }
        return DEFAULT_PAGE_SIZE;
    }

    // 设置下一页游标值
    private static <T> void setNextCursor(PageResult<T> pageResult, List<T> records) {
        if (records.isEmpty()) return;

        try {
            // 获取类型
            Class<?> tClass = records.get(0).getClass();
            // 使用反射获取主键值
            T lastItem = records.get(records.size() - 1);
            Field field = CursorUtils.getCachedCursorField(tClass);
            field.setAccessible(true);
            Object value = field.get(lastItem);

            if (value instanceof Number) {
                long cursorValue = ((Number) value).longValue();
                pageResult.setNextCursor(String.valueOf(cursorValue));
            }
        } catch (Exception e) {
            log.error("Failed to set next cursor", e);
        }
    }

}